From 4637a04d3edf33f502914582486fb3b591622600 Mon Sep 17 00:00:00 2001 From: "cl349@arcadians.cl.cam.ac.uk" Date: Fri, 19 Nov 2004 14:02:29 +0000 Subject: [PATCH] bitkeeper revision 1.1159.179.11 (419dfcf5D6fLg4ewlxJ8pXQaNbvyLw) manage.c, irq.h: Add teardown_irq to uninstall irq's installed with setup_irq. ctrl_if.c: Use teardown_irq instead of SA_STATIC_ACTION. manage.c, irq.h: new file --- .rootkeys | 2 + .../arch/xen/kernel/ctrl_if.c | 4 +- .../include/linux/irq.h | 97 +++++ .../kernel/irq/manage.c | 376 ++++++++++++++++++ 4 files changed, 476 insertions(+), 3 deletions(-) create mode 100644 linux-2.6.10-rc2-xen-sparse/include/linux/irq.h create mode 100644 linux-2.6.10-rc2-xen-sparse/kernel/irq/manage.c diff --git a/.rootkeys b/.rootkeys index 70089fcc37..4152ff07fe 100644 --- a/.rootkeys +++ b/.rootkeys @@ -245,7 +245,9 @@ 4122466356eIBnC9ot44WSVVIFyhQA linux-2.6.10-rc2-xen-sparse/include/asm-xen/queues.h 3f689063BoW-HWV3auUJ-OqXfcGArw linux-2.6.10-rc2-xen-sparse/include/asm-xen/xen_proc.h 419b4e93z2S0gR17XTy8wg09JEwAhg linux-2.6.10-rc2-xen-sparse/include/linux/gfp.h +419dfc609zbti8rqL60tL2dHXQ_rvQ linux-2.6.10-rc2-xen-sparse/include/linux/irq.h 4124f66f4NaKNa0xPiGGykn9QaZk3w linux-2.6.10-rc2-xen-sparse/include/linux/skbuff.h +419dfc6awx7w88wk6cG9P3mPidX6LQ linux-2.6.10-rc2-xen-sparse/kernel/irq/manage.c 40f56a0ddHCSs3501MY4hRf22tctOw linux-2.6.10-rc2-xen-sparse/mkbuildtree 412f46c0LJuKAgSPGoC0Z1DEkLfuLA linux-2.6.10-rc2-xen-sparse/mm/memory.c 410a94a4KT6I6X0LVc7djB39tRDp4g linux-2.6.10-rc2-xen-sparse/mm/page_alloc.c diff --git a/linux-2.6.10-rc2-xen-sparse/arch/xen/kernel/ctrl_if.c b/linux-2.6.10-rc2-xen-sparse/arch/xen/kernel/ctrl_if.c index 78195fa1ab..cf503340a7 100644 --- a/linux-2.6.10-rc2-xen-sparse/arch/xen/kernel/ctrl_if.c +++ b/linux-2.6.10-rc2-xen-sparse/arch/xen/kernel/ctrl_if.c @@ -462,7 +462,7 @@ ctrl_if_unregister_receiver( void ctrl_if_suspend(void) { - free_irq(ctrl_if_irq, NULL); + teardown_irq(ctrl_if_irq, &ctrl_if_irq_action); unbind_evtchn_from_irq(ctrl_if_evtchn); } @@ -496,11 +496,9 @@ void ctrl_if_resume(void) ctrl_if_evtchn = xen_start_info.domain_controller_evtchn; ctrl_if_irq = bind_evtchn_to_irq(ctrl_if_evtchn); -#define SA_STATIC_ACTION 0x01000000 /* so that free_irq() doesn't do kfree() */ memset(&ctrl_if_irq_action, 0, sizeof(ctrl_if_irq_action)); ctrl_if_irq_action.handler = ctrl_if_interrupt; ctrl_if_irq_action.name = "ctrl-if"; - ctrl_if_irq_action.flags = SA_STATIC_ACTION; (void)setup_irq(ctrl_if_irq, &ctrl_if_irq_action); } diff --git a/linux-2.6.10-rc2-xen-sparse/include/linux/irq.h b/linux-2.6.10-rc2-xen-sparse/include/linux/irq.h new file mode 100644 index 0000000000..12584aa5b4 --- /dev/null +++ b/linux-2.6.10-rc2-xen-sparse/include/linux/irq.h @@ -0,0 +1,97 @@ +#ifndef __irq_h +#define __irq_h + +/* + * Please do not include this file in generic code. There is currently + * no requirement for any architecture to implement anything held + * within this file. + * + * Thanks. --rmk + */ + +#include + +#if !defined(CONFIG_ARCH_S390) + +#include +#include +#include +#include + +#include +#include + +/* + * IRQ line status. + */ +#define IRQ_INPROGRESS 1 /* IRQ handler active - do not enter! */ +#define IRQ_DISABLED 2 /* IRQ disabled - do not enter! */ +#define IRQ_PENDING 4 /* IRQ pending - replay on enable */ +#define IRQ_REPLAY 8 /* IRQ has been replayed but not acked yet */ +#define IRQ_AUTODETECT 16 /* IRQ is being autodetected */ +#define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */ +#define IRQ_LEVEL 64 /* IRQ level triggered */ +#define IRQ_MASKED 128 /* IRQ masked - shouldn't be seen again */ +#define IRQ_PER_CPU 256 /* IRQ is per CPU */ + +/* + * Interrupt controller descriptor. This is all we need + * to describe about the low-level hardware. + */ +struct hw_interrupt_type { + const char * typename; + unsigned int (*startup)(unsigned int irq); + void (*shutdown)(unsigned int irq); + void (*enable)(unsigned int irq); + void (*disable)(unsigned int irq); + void (*ack)(unsigned int irq); + void (*end)(unsigned int irq); + void (*set_affinity)(unsigned int irq, cpumask_t dest); +}; + +typedef struct hw_interrupt_type hw_irq_controller; + +/* + * This is the "IRQ descriptor", which contains various information + * about the irq, including what kind of hardware handling it has, + * whether it is disabled etc etc. + * + * Pad this out to 32 bytes for cache and indexing reasons. + */ +typedef struct irq_desc { + unsigned int status; /* IRQ status */ + hw_irq_controller *handler; + struct irqaction *action; /* IRQ action list */ + unsigned int depth; /* nested irq disables */ + unsigned int irq_count; /* For detecting broken interrupts */ + unsigned int irqs_unhandled; + spinlock_t lock; +} ____cacheline_aligned irq_desc_t; + +extern irq_desc_t irq_desc [NR_IRQS]; + +#include /* the arch dependent stuff */ + +extern int setup_irq(unsigned int irq, struct irqaction * new); +extern int teardown_irq(unsigned int irq, struct irqaction * old); + +#ifdef CONFIG_GENERIC_HARDIRQS +extern cpumask_t irq_affinity[NR_IRQS]; +extern int no_irq_affinity; +extern int noirqdebug_setup(char *str); + +extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, + struct irqaction *action); +extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); +extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret); +extern void report_bad_irq(unsigned int irq, irq_desc_t *desc, int action_ret); +extern int can_request_irq(unsigned int irq, unsigned long irqflags); + +extern void init_irq_proc(void); +#endif + +extern hw_irq_controller no_irq_type; /* needed in every arch ? */ + +#endif + +#endif /* __irq_h */ diff --git a/linux-2.6.10-rc2-xen-sparse/kernel/irq/manage.c b/linux-2.6.10-rc2-xen-sparse/kernel/irq/manage.c new file mode 100644 index 0000000000..0c69a28669 --- /dev/null +++ b/linux-2.6.10-rc2-xen-sparse/kernel/irq/manage.c @@ -0,0 +1,376 @@ +/* + * linux/kernel/irq/manage.c + * + * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar + * + * This file contains driver APIs to the irq subsystem. + */ + +#include +#include +#include +#include + +#include "internals.h" + +#ifdef CONFIG_SMP + +/** + * synchronize_irq - wait for pending IRQ handlers (on other CPUs) + * + * This function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. + */ +void synchronize_irq(unsigned int irq) +{ + struct irq_desc *desc = irq_desc + irq; + + while (desc->status & IRQ_INPROGRESS) + cpu_relax(); +} + +EXPORT_SYMBOL(synchronize_irq); + +#endif + +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables and Enables are + * nested. + * Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ +void disable_irq_nosync(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(disable_irq_nosync); + +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Enables and Disables are + * nested. + * This function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. + */ +void disable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + + disable_irq_nosync(irq); + if (desc->action) + synchronize_irq(irq); +} + +EXPORT_SYMBOL(disable_irq); + +/** + * enable_irq - enable handling of an irq + * @irq: Interrupt to enable + * + * Undoes the effect of one call to disable_irq(). If this + * matches the last disable, processing of interrupts on this + * IRQ line is re-enabled. + * + * This function may be called from IRQ context. + */ +void enable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 0: + WARN_ON(1); + break; + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + + desc->status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } + desc->handler->enable(irq); + /* fall-through */ + } + default: + desc->depth--; + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(enable_irq); + +/* + * Internal function that tells the architecture code whether a + * particular irq has been exclusively allocated or is available + * for driver use. + */ +int can_request_irq(unsigned int irq, unsigned long irqflags) +{ + struct irqaction *action; + + if (irq >= NR_IRQS) + return 0; + + action = irq_desc[irq].action; + if (action) + if (irqflags & action->flags & SA_SHIRQ) + action = NULL; + + return !action; +} + +/* + * Internal function to register an irqaction - typically used to + * allocate special interrupts that are part of the architecture. + */ +int setup_irq(unsigned int irq, struct irqaction * new) +{ + struct irq_desc *desc = irq_desc + irq; + struct irqaction *old, **p; + unsigned long flags; + int shared = 0; + + if (desc->handler == &no_irq_type) + return -ENOSYS; + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&desc->lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + desc->depth = 0; + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | + IRQ_WAITING | IRQ_INPROGRESS); + if (desc->handler->startup) + desc->handler->startup(irq); + else + desc->handler->enable(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + new->irq = irq; + register_irq_proc(irq); + new->dir = NULL; + register_handler_proc(irq, new); + + return 0; +} + +/* + * Internal function to unregister an irqaction - typically used to + * deallocate special interrupts that are part of the architecture. + */ +int teardown_irq(unsigned int irq, struct irqaction * old) +{ + struct irq_desc *desc; + struct irqaction **p; + unsigned long flags; + + if (irq >= NR_IRQS) + return -ENOENT; + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + for (;;) { + struct irqaction * action = *p; + + if (action) { + struct irqaction **pp = p; + + p = &action->next; + if (action != old) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!desc->action) { + desc->status |= IRQ_DISABLED; + if (desc->handler->shutdown) + desc->handler->shutdown(irq); + else + desc->handler->disable(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + unregister_handler_proc(irq, action); + + /* Make sure it's not being used on another CPU */ + synchronize_irq(irq); + return 0; + } + printk(KERN_ERR "Trying to teardown free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); + return -ENOENT; + } +} + +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. The function + * does not return until any executing interrupts for this IRQ + * have completed. + * + * This function must not be called from interrupt context. + */ +void free_irq(unsigned int irq, void *dev_id) +{ + struct irq_desc *desc; + struct irqaction *action; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + for (action = desc->action; action != NULL; action = action->next) { + if (action->dev_id != dev_id) + continue; + + spin_unlock_irqrestore(&desc->lock,flags); + + if (teardown_irq(irq, action) == 0) + kfree(action); + return; + } + printk(KERN_ERR "Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); + return; +} + +EXPORT_SYMBOL(free_irq); + +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * SA_INTERRUPT Disable local interrupts while processing + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ +int request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, void *dev_id) +{ + struct irqaction * action; + int retval; + + /* + * Sanity-check: shared interrupts must pass in a real dev-ID, + * otherwise we'll have trouble later trying to figure out + * which interrupt is which (messes up the interrupt freeing + * logic etc). + */ + if ((irqflags & SA_SHIRQ) && !dev_id) + return -EINVAL; + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + cpus_clear(action->mask); + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + + return retval; +} + +EXPORT_SYMBOL(request_irq); + -- 2.30.2